package com.stars.easyms.logger.support.logback.pattern.converter;

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.CoreConstants;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>className: EasyMsDateConverter</p>
 * <p>description: 重写DateConverter类</p>
 *
 * @author guoguifang
 * @date 2019-08-21 15:07
 * @since 1.3.0
 */
public final class EasyMsDateConverter extends ClassicConverter {

    private static final int MAX_CACHE_SIZE = 1024;

    private static final Map<String, Map<Long, String>> DATE_CACHE = new ConcurrentHashMap<>(8);

    private static volatile long lastClearTime = System.currentTimeMillis();

    private String datePattern;

    private DateTimeFormatter dateTimeFormatter;

    private ZoneId zoneId = ZoneId.systemDefault();

    @Override
    public void start() {
        datePattern = getFirstOption();
        if (datePattern == null) {
            datePattern = CoreConstants.ISO8601_PATTERN;
        }
        if (datePattern.equals(CoreConstants.ISO8601_STR)) {
            datePattern = CoreConstants.ISO8601_PATTERN;
        }
        try {
            dateTimeFormatter = DateTimeFormatter.ofPattern(datePattern);
        } catch (IllegalArgumentException e) {
            addWarn("Could not instantiate SimpleDateFormat with pattern " + datePattern, e);
            datePattern = CoreConstants.ISO8601_PATTERN;
            dateTimeFormatter = DateTimeFormatter.ofPattern(datePattern);
        }
        DATE_CACHE.putIfAbsent(datePattern, new ConcurrentHashMap<>(MAX_CACHE_SIZE));
        List<String> optionList = getOptionList();
        if (optionList != null && optionList.size() > 1) {
            TimeZone tz = TimeZone.getTimeZone(optionList.get(1));
            zoneId = tz.toZoneId();
        }
    }

    @Override
    public String convert(ILoggingEvent le) {
        long currTime = System.currentTimeMillis();
        Map<Long, String> datePatternCache = DATE_CACHE.get(datePattern);
        if (currTime - lastClearTime > 10000 || datePatternCache.size() > MAX_CACHE_SIZE) {
            setLastClearTime(currTime);
            datePatternCache.clear();
        }
        return datePatternCache.computeIfAbsent(le.getTimeStamp(), key -> ZonedDateTime.ofInstant(Instant.ofEpochMilli(key), zoneId).format(dateTimeFormatter));
    }

    private static void setLastClearTime(long currTime) {
        lastClearTime = currTime;
    }
}